﻿using System.Linq;
using TouchSocket.Core;
using TouchSocket.Sockets;

namespace TK.TSocket
{
    /// <summary>
    /// 连接前处理插件
    /// Order = 999999;
    /// </summary>
    public class InitHandlerPlug : TcpPluginBase<ISocketClient>
    {
        private readonly TcpSocketServerConfig _config;
        private readonly IReceiveData _receiveData;

        /// <summary>
        /// ctor
        /// </summary>
        public InitHandlerPlug(
            TcpSocketServerConfig config,
            IReceiveData receiveData)
        {
            _config = config;
            _receiveData = receiveData;
            Order = 999999;
        }

        #region base methods
        /// <summary>
        /// OnConnecting
        /// </summary>
        protected override void OnConnecting(ISocketClient client, OperationEventArgs e)
        {
            ConnectHandle(client, e);
            base.OnConnecting(client, e);
        }

        /// <summary>
        /// OnConnected
        /// </summary>
        protected override void OnConnected(ISocketClient client, TouchSocketEventArgs e)
        {
            var dataPacket = CreateDataPacket(client, DataType.Connect);
            dataPacket.Message = "连接成功";
            _receiveData.ReceiveDataAsync(dataPacket);
            base.OnConnected(client, e);
        }

        /// <summary>
        /// OnDisconnected
        /// </summary>
        protected override void OnDisconnected(ISocketClient client, DisconnectEventArgs e)
        {
            DisconnectHandle(client, e);
            base.OnDisconnected(client, e);
        }

        /// <summary>
        /// OnReceivingData,数据适配器前
        /// </summary>
        protected override void OnReceivingData(ISocketClient client, ByteBlockEventArgs e)
        {
            //首次接收数据包
            if (_config.ActionType == AdapterActionType.Receive && DataCollection.FirstPacketDic.GetValue(client.ID))
            {
                //增加tcp数据处理协议
                var oldPosition = e.ByteBlock.Pos;
                var data = new byte[e.ByteBlock.Len];
                e.ByteBlock.Read(data, 0, data.Length);
                e.ByteBlock.Pos= oldPosition;
                var dataAdapter = _config.DataAdapterFunc?.Invoke(ToAdapterConfig(client, data:data));
                if (dataAdapter != null)
                    client.SetDataHandlingAdapter(dataAdapter);
                DataCollection.FirstPacketDic.Remove(client.ID);
            }

            base.OnReceivingData(client, e);
        }
        #endregion

        #region private methods
        /// <summary>
        /// 连接事件里处理
        /// </summary>
        private void ConnectHandle(ISocketClient client, OperationEventArgs e)
        {
            var packet = CreateDataPacket(client, DataType.Connect);
            packet.Message = "请求连接";
            //ip限制
            if (IpLimit(client, e))
            {
                packet.DataType = DataType.Other;
                packet.Message = "禁止连接";
                _receiveData.ReceiveDataAsync(packet);
                return;
            }

            if (_config.ActionType == AdapterActionType.Connect)
            {
                //增加tcp数据处理协议      
                var dataAdapter = _config.DataAdapterFunc?.Invoke(ToAdapterConfig(client, e.ID));
                if (dataAdapter != null)
                    client.SetDataHandlingAdapter(dataAdapter);
            }

            DataCollection.FirstPacketDic.Add(e.ID, true);   
            _receiveData.ReceiveDataAsync(packet);
        }

        /// <summary>
        /// ip连接限制；true禁止连接；fale允许连接
        /// </summary>
        private bool IpLimit(ISocketClient client, OperationEventArgs e)
        {
            if (_config.IpWhiteList.Any())
            {
                if (_config.IpWhiteList.Contains(client.IP))
                {
                    return false;
                }
                else
                {
                    e.IsPermitOperation = false;
                    e.Handled = true;
                    return true;
                }
            }
            else if (_config.IpBlackList.Contains(client.IP))
            {
                e.IsPermitOperation = false;
                e.Handled = true;
                return true;
            }

            return false;
        }

        /// <summary>
        /// 断开事件处理
        /// </summary>
        private void DisconnectHandle(ISocketClient client, DisconnectEventArgs e)
        {
            DataCollection.FirstPacketDic.Remove(client.ID);
            e.Handled = true;
            DataPacket dataPacket = CreateDataPacket(client, DataType.DisConnect);
            dataPacket.Message = $"连接{(e.Manual ? "主" : "被")}动关闭,{e.Message}";
            _receiveData.ReceiveDataAsync(dataPacket);
        }

        /// <summary>
        /// 创建数据包
        /// </summary>
        private DataPacket CreateDataPacket(ISocketClient client, DataType dataType)
        {
            return new DataPacket
            {
                ServerIp = client.ServiceIP,
                ServerPort = client.ServicePort,
                ClientIp = client.IP,
                ClientPort = client.Port,
                ClientId = client.ID,
                DataType = dataType,
            };
        }

        /// <summary>
        /// 生成适配器包
        /// </summary>
        private TcpAdapterConfig ToAdapterConfig(ISocketClient client, string clientId = null, byte[] data = null)
        {
            return new TcpAdapterConfig
            {
                ServerIp = client.ServiceIP,
                ServerPort = client.ServicePort,
                ClientIp = client.IP,
                ClientPort = client.Port,
                ClientId = string.IsNullOrWhiteSpace(client.ID) ? clientId : client.ID,
                Data = data
            };
        }
        #endregion
    }
}
